package com.ruoyi.game.controller;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.game.constant.GameRoomProperties;
import com.ruoyi.game.core.*;
import com.ruoyi.game.core.card.BasePoker;
import com.ruoyi.game.core.exception.GameOpException;
import com.ruoyi.game.domain.GamePlayer;
import com.ruoyi.game.domain.GameRoom;
import com.ruoyi.game.controller.dto.*;
import com.ruoyi.game.service.IGamePlayerService;
import com.ruoyi.game.websocket.handler.GameWebSocketHandler;
import com.ruoyi.game.websocket.handler.MockRobotSession;
import com.ruoyi.game.websocket.message.packet.ReadyReq;
import com.ruoyi.game.websocket.session.SessionInfo;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.game.service.IGameRoomService;
import org.springframework.web.socket.WebSocketSession;

/**
 * 房间Controller
 *
 * @author ruoyi
 * @date 2025-04-18
 */

@Slf4j
@Api(tags = "游戏房间管理接口")
@RestController
@RequiredArgsConstructor
@RequestMapping("/game/room")
public class GameRoomController extends BaseController {

    private final IGameRoomService gameRoomService;
    private final IGamePlayerService gamePlayerService;
    private final TokenService tokenService;
    private final GameRoomProperties gameRoomProperties;
    private final AtomicLong robotIdGenerator = new AtomicLong(-1000);


    /** 查询房间列表 */
    @ApiOperation("查询房间列表")
    @GetMapping("/list")
    public TableDataInfo list(GameRoom gameRoom) {
        log.info("[房间列表] 查询条件: {}", gameRoom);
//        startPage();
        List<GameRoom> list = gameRoomService.selectGameRoomList(gameRoom);
        log.info("[房间列表] 查询结果数量: {}", list.size());
        return getDataTable(list);
    }


    @ApiOperation("导出房间列表")
    @PostMapping("/export")
    public void export(HttpServletResponse response, GameRoom gameRoom) {
        log.info("[导出房间] 查询条件: {}", gameRoom);
        List<GameRoom> list = gameRoomService.selectGameRoomList(gameRoom);
        ExcelUtil<GameRoom> util = new ExcelUtil<>(GameRoom.class);
        log.info("[导出房间] 导出数据数量: {}", list.size());
        util.exportExcel(response, list, "房间数据");
    }

    @ApiOperation("获取房间详细信息（数据库记录）")
    @ApiImplicitParam(name = "roomId", value = "房间ID", required = true, dataType = "Long", paramType = "path")
    @GetMapping(value = "/{roomId}")
    public AjaxResult getInfo(@PathVariable("roomId") Long roomId) {
        log.info("[房间详情] 查询 roomId={}", roomId);
        return success(gameRoomService.selectGameRoomById(roomId));
    }

    @ApiOperation("根据房间号查询房间ID")
    @ApiImplicitParam(name = "roomCode", value = "房间号", required = true, dataType = "String", paramType = "query")
    @GetMapping("/findRoomId")
    public AjaxResult findRoomIdByCode(@RequestParam("roomCode") String roomCode) {
        log.info("[房间查询] 根据 roomCode={} 查询房间ID", roomCode);
        GameRoom room = gameRoomService.selectGameRoomByCode(roomCode);
        if (room == null) {
            log.warn("[房间查询] 未找到房间，roomCode={}", roomCode);
            return AjaxResult.error("房间不存在");
        }
        return AjaxResult.success(room.getId());
    }

    @ApiOperation("获取房间实时状态（内存）")
    @ApiImplicitParam(name = "roomId", value = "房间ID", required = true, dataType = "Long", paramType = "path")
    @GetMapping("/{roomId}/info")
    public AjaxResult getRoomInfo(@PathVariable Long roomId) {
        log.info("[房间状态] 请求房间 roomId={}", roomId);
        GameRoomCore room = gameRoomService.getRoom(roomId);
        if (room == null) {
            log.warn("[房间状态] 房间不存在 roomId={}", roomId);
            return AjaxResult.error("房间不存在");
        }
        return AjaxResult.success(room.buildRoomInfo());
    }

    @ApiOperation("创建房间")
    @ApiResponses({
            @ApiResponse(code = 200, message = "房间创建成功")
    })
    @PostMapping("/create")
    public AjaxResult createRoom(
            @ApiParam(name = "request", value = "创建房间参数", required = true)
            @RequestBody @Validated CreateRoomReq request, HttpServletRequest httpRequest) throws IOException {

        log.info("[创建房间] 请求参数: {}", request);

        // 1. 从 token 里解析 playerId
        LoginUser loginUser = tokenService.getLoginUser(httpRequest);
        if (loginUser == null) {
            return AjaxResult.error("未登录或登录已失效");
        }
        Long playerId = loginUser.getUserId(); // 这里拿到玩家ID
        log.info("[加入房间] 当前登录玩家ID={}", playerId);
        Long ownerId = playerId;

        String roomKey = generateUniqueRoomKey();

        boolean robotRoom = Boolean.TRUE.equals(request.getRobot());
        int robotNum = request.getRobotNum() ==0 ? gameRoomProperties.getMaxPlayers() : request.getRobotNum();

        if (!robotRoom) {
            GamePlayer owner = gamePlayerService.selectGamePlayerById(ownerId);
            if (owner == null) {
                return AjaxResult.error("房主不存在");
            }
            Long roomCard = owner.getRoomCard() != null ? owner.getRoomCard() : 0L;
            if (roomCard < 1) {
                return AjaxResult.error("房卡不足，无法创建房间");
            }
        }

        GameRoom gameRoom = new GameRoom();
        gameRoom.setRoomCode(roomKey);
        gameRoom.setOwnerId(ownerId);
        gameRoom.setPlayerNum(5);
        gameRoom.setStatus(0);
        gameRoomService.insertGameRoom(gameRoom);

        GameRoomCore roomCore = gameRoomService.createRoom(gameRoom.getId(), roomKey, robotRoom);
        log.info("[创建房间] 房间已初始化: id={}, code={}", gameRoom.getId(), roomKey);

        if (robotRoom) {
            log.info("[创建房间] 房间为机器人房，初始化机器人...");
            for (int i = 0; i < robotNum; i++) {
                GamePlayer robot = mockRobot(i);
                WebSocketSession mockSession = new MockRobotSession(robot.getId());

                GameWebSocketHandler.SESSION_INFO.put(mockSession, new SessionInfo(robot.getId(), roomCore.getRoomId()));
                GameWebSocketHandler.ROOM_SESSIONS.computeIfAbsent(roomCore.getRoomId(), k -> ConcurrentHashMap.newKeySet()).add(mockSession);

                roomCore.join(robot);
                log.info("[机器人] 加入并入座: id={}, seat={}", robot.getId(), i);

                ReadyReq readyReq = new ReadyReq(true);
                gameRoomService.ready(mockSession, readyReq);
                log.info("[机器人] 自动准备: id={}", robot.getId());
            }
        }

        return AjaxResult.success("房间创建成功")
                .put("room", Map.of(
                        "id", gameRoom.getId(),
                        "roomCode", gameRoom.getRoomCode(),
                        "ownerId", gameRoom.getOwnerId(),
                        "playerNum", gameRoom.getPlayerNum(),
                        "status", gameRoom.getStatus()
                ));
    }

    private GamePlayer mockRobot(int index) {
        GamePlayer p = new GamePlayer();
        p.setId(robotIdGenerator.getAndDecrement()); // 保证每个机器人 ID 唯一且为负数
        p.setNickname("机器人" + p.getId());
        p.setAvatar("https://example.com/bot" + (index + 1) + ".png");
        p.setSex(index % 2 == 0 ? 1 : 0);
        p.setIsRobot(true);
        p.setUsername("bot" + (index + 1));
        p.setPassword("bcrypt-mock");
        p.setRoomCard(999L);
        return p;
    }

    private String generateUniqueRoomKey() {
        Random random = new Random();
        String roomKey;
        int retry = 0;
        do {
            roomKey = String.format("%06d", random.nextInt(1_000_000));
            retry++;
            if (retry > 10) {
                log.error("[生成房号] 重试超过限制");
                throw new IllegalStateException("生成唯一房号失败，请稍后重试");
            }
        } while (gameRoomService.existsByRoomCode(roomKey));
        log.info("[生成房号] 成功生成 roomCode={}", roomKey);
        return roomKey;
    }

    @ApiOperation("校验出牌是否合法")
    @PostMapping("/checkCard")
    public AjaxResult checkCardOp(@RequestBody CheckOpReq req, HttpServletRequest httpRequest) {
        LoginUser loginUser = tokenService.getLoginUser(httpRequest);
        if (loginUser == null) {
            log.warn("[CheckCardOp] 登录失效，拒绝访问");
            return AjaxResult.error("未登录或登录已失效");
        }

        Long playerId = loginUser.getUserId(); // 这里拿到玩家ID

        if (req.getCards() == null) {
            log.warn("[CheckCardOp] 参数非法：cards 为 null，playerId={}, opType={}", playerId, req.getOpType());
            return AjaxResult.error("参数错误：cards 不能为空");
        }

        log.info("[CheckCardOp] 玩家请求校验出牌是否合法，playerId={}，请求内容：opType={}，cards={}",
                playerId, req.getOpType(), BasePoker.toCardString(req.getCards()));

        try {
            CheckOpResp resp = gameRoomService.checkCardOp(req, playerId);
            log.info("[CheckCardOp] 校验结果：valid={}，message={}", resp.isValid(), resp.getMessage());
            return AjaxResult.success(resp);
        } catch (GameOpException e) {
            log.warn("[CheckCardOp] 游戏操作异常：{}", e.getMessage());
            return AjaxResult.error(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            log.error("[CheckCardOp] 系统错误：{}", e.getMessage());
            return AjaxResult.error("系统错误：" + e.getMessage());
        }
    }


    /** 新增房间 (保留原有接口) */
//    @ApiOperation("新增房间（后台）")
    @PostMapping
    public AjaxResult add(@RequestBody GameRoom gameRoom) {
        return toAjax(gameRoomService.insertGameRoom(gameRoom));
    }

    /** 修改房间 */
//    @ApiOperation("修改房间（后台）")
    @PutMapping
    public AjaxResult edit(@RequestBody GameRoom gameRoom) {
        return toAjax(gameRoomService.updateGameRoom(gameRoom));
    }

    /** 删除房间 */
//    @ApiOperation("删除房间（后台）")
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(gameRoomService.deleteGameRoomByIds(ids));
    }
}
